import { h } from './lib/core';
import {createElement} from "./lib/createElement";
import { nodePatchTypes, propPatchTypes } from './constants/dom';

function view() {
  return (
    <div>
      Hello World
      <ul>
        {
          // 生成元素为0到n-1的数组
          [...Array(state.num).keys()]
            .map( i => (
              <li id={i} class={`li-${i}`}>
                第{i * state.num}
              </li>
            ))
        }
      </ul>
    </div>
  );
}

let state = { num: 5 };
let timer;
let prevDom;


function tick(element) {
  if (state.num > 20) {
    clearTimeout(timer);
    return;
  }
  const newVDom = view();
  // 生成差异对象
  const patchObj = diff(prevDom, newVDom);

  prevDom = newVDom;

  // 给dom打个补丁
  patch(element, patchObj);
}

function diff(oldVDom, newVDom) {
  // create node
  if (typeof oldVDom === 'undefined') {
    return {
      type: nodePatchTypes.CREATE,
      vdom: newVDom,
    }
  }
  // remove node
  if (typeof newVDom === 'undefined') {
    return {
      type: nodePatchTypes.REMOVE,
    }
  }
  // update node
  if (oldVDom.tag) {
    // 比较props的变化
    const propsDiff = diffProps(oldVDom, newVDom);

    // 比较children的变化
    const childrenDiff = diffChildren(oldVDom, newVDom);
    // 如果props或者children有变化，才需要更新
    if (propsDiff.length > 0 || childrenDiff.some(patchObj => (patchObj !== undefined) )) {
      return {
        type: nodePatchTypes.UPDATE,
        props: propsDiff,
        children: childrenDiff
      }
    }
  }

}

// 比较props的变化
function diffProps(oldVDom, newVDom) {
  const patches = [];

  const allProps = {...oldVDom.props, ...newVDom.props};

  // 获取新旧所有属性名后，再逐一判断新旧属性值
  Object.keys(allProps).forEach((key) => {
      const oldValue = oldVDom.props[key];
      const newValue = newVDom.props[key];

      // 删除属性
      if (typeof newValue === 'undefined') {
        patches.push({
          type: propPatchTypes.REMOVE,
          key
        });
      }
      // 更新属性
      else if (typeof newValue === 'undefined' || oldValue !== newValue) {
        patches.push({
          type: propPatchTypes.UPDATE,
          key,
          value: newValue
        });
      }
    }
  );

  return patches;
}

// 比较children的变化
function diffChildren(oldVDom, newVDom) {
  const patches = [];

  // 获取子元素最大长度
  const childLength = Math.max(oldVDom.children.length, newVDom.children.length);

  // 遍历并diff子元素
  for (let i = 0; i < childLength; i++) {
    patches.push(diff(oldVDom.children[i], newVDom.children[i]));
  }

  return patches;
}

// 给dom打个补丁
function patch(parent, patchObj, index=0) {
  if (!patchObj) {
    return;
  }

  // 新建元素
  if (patchObj.type === nodePatchTypes.CREATE) {
    return parent.appendChild(createElement(patchObj.vdom));
  }

  const element = parent.childNodes[index];

  // 删除元素
  if (patchObj.type === nodePatchTypes.REMOVE) {
    return parent.removeChild(element);
  }

  // 替换元素
  if (patchObj.type === nodePatchTypes.REPLACE) {
    return parent.replaceChild(createElement(patchObj.vdom), element);
  }

  // 更新元素
  if (patchObj.type === nodePatchTypes.UPDATE) {
    const {props, children} = patchObj;

    // 更新属性
    patchProps(element, props);

    // 更新子元素
    children.forEach( (patchObj, i) => {
      // 更新子元素时，需要将子元素的序号传入
      patch(element, patchObj, i)
    });
  }
}

// 更新属性
function patchProps(element, props) {
  if (!props) {
    return;
  }

  props.forEach( patchObj => {
    // 删除属性
    if (patchObj.type === propPatchTypes.REMOVE) {
      element.removeAttribute(patchObj.key);
    }
    // 更新或新建属性
    else if (patchObj.type === propPatchTypes.UPDATE) {
      element.setAttribute(patchObj.key, patchObj.value);
    }
  })
}


function render(el) {
  console.log(view());
  const vDom = view();
  prevDom = vDom;

  const dom = createElement(vDom);
  el.appendChild(dom);

  timer = setInterval(() => {
    state.num += 1;
    tick(el);
  }, 500);

}

render(document.getElementById('app'), view);
